/**
* Oxide
*
* Copyright (c) 2011 Dinosaur Kick Pty Ltd, All rights reserved.
*
* This source code is made available under the "Modified BSD" licensing arrangement.
* See license.txt for details.
*/
// ----------------------------------------------------------------------------
#include <string>
// ----------------------------------------------------------------------------
#ifndef O2_AST_NODE_INC
#define O2_AST_NODE_INC
namespace o2 {
namespace ast {
// ----------------------------------------------------------------------------

template <typename StringT>
class basic_visitor_base;

template <typename StringT>
struct basic_node
{
	O2_AST_TYPEDEFS(StringT);
	typedef StringT string_type;
	typedef basic_visitor_base<string_type> visitor_type;

	virtual ~basic_node(void)
		{ }
		
	virtual void accept(visitor_type& vis) const = 0;
};

// ----------------------------------------------------------------------------

#define O2_AST_CONCRETE_NODE_BEGIN(name, base) \
	template <typename StringT> \
	struct basic_ ## name : public node_base<StringT, basic_ ## name, basic_ ## base> \
	{ \
		typedef StringT string_type; \
		typedef basic_ ## base<string_type> base_type; \
		typedef basic_ ## name<string_type> self_type; \
		O2_AST_TYPEDEFS(string_type);

#define O2_AST_CONCRETE_NODE_END(name) \
		}; \
		typedef basic_ ## name<std::string> name; \
		typedef basic_ ## name<std::wstring> w ## name;

// ----------------------------------------------------------------------------

#define O2_AST_ABSTRACT_NODE_BEGIN(name, base) \
	template <typename StringT> \
	struct basic_ ## name : public basic_ ## base<StringT> \
	{ \
		typedef StringT string_type; \
		typedef basic_ ## base<string_type> base_type; \
		typedef basic_ ## name<string_type> self_type; \
		O2_AST_TYPEDEFS(string_type);

#define O2_AST_ABSTRACT_NODE_END(name) \
		O2_AST_CONCRETE_NODE_END(name)

#define O2_AST_ABSTRACT_NODE(name, base) \
		O2_AST_ABSTRACT_NODE_BEGIN(name, base) \
		O2_AST_ABSTRACT_NODE_END(name)

// ----------------------------------------------------------------------------

template
<
	typename StringT,
	template <typename> class DerivedT,
	template <typename> class BaseT = basic_node
>
struct node_base
	: public BaseT<StringT>
{
	O2_AST_TYPEDEFS(StringT);
	typedef StringT string_type;
	typedef basic_visitor_base<string_type> visitor_type;
	typedef DerivedT<string_type> derived_type;

	virtual void accept(visitor_type& vis) const
		{ vis.visit_interface(static_cast<const derived_type&>(*this)); }
};

// ----------------------------------------------------------------------------

typedef basic_node<std::string> node;
typedef basic_node<std::wstring> wnode;

// ----------------------------------------------------------------------------
} // namespace ast
} // namespace o2
#endif // O2_AST_NODE_INC
// ----------------------------------------------------------------------------
